package com.framework.bdf4j.sysadm.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import com.amazonaws.services.s3.model.S3Object;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.framework.bdf4j.comm.util.FileUtils;
import com.framework.bdf4j.comm.util.R;
import com.framework.bdf4j.comm.web.WebUtil;
import com.framework.bdf4j.sysadm.entity.SysFile;
import com.framework.bdf4j.sysadm.mapper.SysFileMapper;
import com.framework.bdf4j.sysadm.service.SysFileService;
import com.sca4cloud.sca.common.oss.OssProperties;
import com.sca4cloud.sca.common.oss.service.OssTemplate;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

/**
 * 文件管理
 *
 */
@Slf4j
@Service
@AllArgsConstructor
public class SysFileServiceImpl extends ServiceImpl<SysFileMapper, SysFile> implements SysFileService {
    
    private final OssProperties ossProperties;
    private final OssTemplate minioTemplate;

    /**
     * 上传文件
     *
     * @param file
     * @return
     */
    @Override
    public R uploadFile(MultipartFile file) {
        String fileName = IdUtil.simpleUUID() + StrUtil.DOT + FileUtil.extName(file.getOriginalFilename());
        Map<String, String> resultMap = new HashMap<>(4);
        resultMap.put("bucketName", ossProperties.getBucketName());
        resultMap.put("fileName", fileName);
        resultMap.put("url", String.format("/admin/file/%s/%s", ossProperties.getBucketName(), fileName));

        try {
            minioTemplate.putObject(ossProperties.getBucketName(), fileName, file.getInputStream());
            // 文件管理数据记录,收集管理追踪文件
            fileLog(file, fileName);
        } catch (Exception e) {
            log.error("上传失败", e);
            return R.failed(e.getLocalizedMessage());
        }
        return R.ok(resultMap);
    }

    /**
     * 读取文件
     *
     * @param bucket
     * @param fileName
     * @param response
     */
    @Override
    public void getFile(String fileName, HttpServletResponse response, HttpServletRequest request) {
        try (S3Object s3Object = minioTemplate.getObject(ossProperties.getBucketName(), fileName)) {
            QueryWrapper<SysFile> sysFileQueryWrapper = new QueryWrapper<>();
            sysFileQueryWrapper.eq("file_name", fileName);
            SysFile sysFile = this.getOne(sysFileQueryWrapper);

            response.setContentType("application/octet-stream; charset=UTF-8");
            response.setHeader("Content-Disposition",
                "attachment;fileName=" + FileUtils.setFileDownloadHeader(request, sysFile.getOriginal()));
            IoUtil.copy(s3Object.getObjectContent(), response.getOutputStream());
        } catch (Exception e) {
            log.error("文件读取异常", e);
        }
    }

    /**
     * 读取文件URL
     *
     * @param bucket
     *            桶名称
     * @param fileName
     *            文件名称
     */
    public String getFileUrl(String fileName) {
        String fUrl = "";
        try {
            fUrl = minioTemplate.getObjectURL(ossProperties.getBucketName(), fileName, 7);
        } catch (Exception e) {
            log.error("获取文件失败", e);
        }
        return fUrl;
    }

    /**
     * 删除文件
     *
     * @param id
     * @return
     */
    @Override
    @SneakyThrows
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteFile(Long id) {
        SysFile file = this.getById(id);
        minioTemplate.removeObject(ossProperties.getBucketName(), file.getFileName());
        return this.removeById(id);
    }

    /**
     * 文件管理数据记录,收集管理追踪文件
     *
     * @param file
     *            上传文件格式
     * @param fileName
     *            文件名
     */
    private void fileLog(MultipartFile file, String fileName) {
        SysFile sysFile = new SysFile();
        // 原文件名
        /*String original =
            CharsetUtil.convert(file.getOriginalFilename(), CharsetUtil.CHARSET_ISO_8859_1, CharsetUtil.CHARSET_UTF_8);*/
        String original = file.getOriginalFilename();
        sysFile.setFileName(fileName);
        sysFile.setOriginal(original);
        sysFile.setFileSize(file.getSize());
        sysFile.setType(FileUtil.extName(original));
        sysFile.setBucketName(ossProperties.getBucketName());
        sysFile.setCreateUser(WebUtil.getHttpCurrentUserName());
        this.save(sysFile);
    }

    /**
     * <b>方法描述：</b> 处理上传的文件 <br/>
     *
     * @param mRequest
     *            上传的文件
     * @param path
     *            保存相对路径
     * @return 字段名称和对应的文件ID列表
     */
    public Map<String, List<String>> handleMultiPart(HttpServletRequest request) {
        Map<String, List<String>> reMap = new HashMap<String, List<String>>();
        try {
            // 创建一个通用的多部分解析器
            CommonsMultipartResolver multipartResolver =
                new CommonsMultipartResolver(request.getSession().getServletContext());
            // 判断 request 是否有文件上传,即多部分请求
            // if (multipartResolver.isMultipart(request)) {
            MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest)request;
            // 取得request中的所有文件名
            Iterator<String> iter = multiRequest.getFileNames();

            while (iter.hasNext()) {
                String fieldName = iter.next();
                // 取得上传文件
                List<MultipartFile> files = multiRequest.getFiles(fieldName);
                if (CollectionUtil.isNotEmpty(files)) {
                    List<String> fidList = new ArrayList<String>();
                    for (MultipartFile file : files) {
                        R rlt = uploadFile(file);
                        if (rlt.getCode() == 0) {
                            Map<String, String> resultMap = (Map<String, String>)rlt.getData();
                            fidList.add(resultMap.get("fileName"));
                        }
                    }
                    reMap.put(fieldName, fidList);
                }
            }
            // }
        } catch (Exception e) {

        }
        return reMap;
    }
}
